<?php
namespace App\Services\Promotion;
use App\Common\ResponseCode;
use App\Exceptions\BusinessException;
use App\Jobs\SecKillRushJob;
use App\Params\H5\SecKillRushParams;
use App\Repository\SecKillRepository;
use App\Services\BaseService;
use App\Traits\DateTimeTrait;
use Illuminate\Support\Facades\Cache;

/**
 * 秒杀相关业务类
 *
 * @author WangBin
 * @date 2021-09-24
 * @package App\Http\Services\Promotion
 */
class SecKillService extends BaseService
{
    use DateTimeTrait;

    private $cacheKey = 'sec-kill-activity-'; // 秒杀活动 key
    private $cacheProductStockKey = 'sec-kill-stock-'; // 秒杀商品库存
    private $cacheActiveKey = 'sec-kill-activity-active';

    /**
     * 秒杀商品
     *
     * @param SecKillRushParams $params
     * @return mixed
     * @throws BusinessException
     */
    public function rush(SecKillRushParams $params)
    {
        // 获取秒杀活动 优先取缓存
        if(Cache::has($this->cacheKey . $params->getSecKillId())) {
            $secKill = json_decode(Cache::get($this->cacheKey . $params->getSecKillId()), true);
        } else {
            $secKill = SecKillRepository::getInstance()->getById($params->getSecKillId());
            if(is_null($secKill)) {
                throw new BusinessException(ResponseCode::SECKILL_NOT_FOUND);
            }
            // 存入缓存
            Cache::put($this->cacheKey . $params->getSecKillId(), json_encode($secKill->toArray()));
            // 库存存入缓存
            Cache::put($this->cacheProductStockKey . $secKill->product_id, $secKill->stock_qty);
            // 活动是否可用存入缓存
            Cache::put($this->cacheActiveKey, $secKill->is_active);
        }
        // 活动是否可用
        if(Cache::get($this->cacheActiveKey) == 0) {
            throw new BusinessException(ResponseCode::SECKILL_NOT_ACCESS);
        }

        // 获取当前时间戳
        $currStamp = $this->getCurrTimeStamp();
        if($currStamp < strtotime($secKill['start_at'])) {
            throw new BusinessException(ResponseCode::SECKILL_NOT_START);
        }
        if($currStamp > strtotime($secKill['end_at'])) {
            // 活动已结束
            Cache::put($this->cacheActiveKey, 0);
            throw new BusinessException(ResponseCode::SECKILL_HAS_END);
        }
        // 库存
        if(Cache::get($this->cacheProductStockKey . $params->getProductId(), 0) < $params->getQty()) {
            throw new BusinessException(ResponseCode::SECKILL_STOCK_EMPTY);
        }
        // 放入队列处理
        SecKillRushJob::dispatch($secKill['seckill_id'], $params->getQty(), $params->getProductId(), $params->getCustomerId());
        return true;
    }
}
